package com.google.code.gaestats;

import com.googlecode.objectify.annotation.EntitySubclass;
import com.googlecode.objectify.annotation.Ignore;
import java.util.List;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.joda.time.Interval;

/**
 *
 * @author JaggardM
 */
@EntitySubclass
public class PerMinuteCounterData extends CounterData
{

	private final static int MINUTES_TO_KEEP = 1440; //60 * 24 = 1 day
	@Ignore
	private List<Interval> unavailableTimes;

	/**
	 * Creates a new instance with an empty set of statistics and the latest time set to the beginning of this minute.
	 */
	public PerMinuteCounterData()
	{
		super(MINUTES_TO_KEEP, new DateTime().withMillisOfSecond(0).withSecondOfMinute(0));
	}

	@Override
	protected int calculateDataPosition(DateTime time)
	{
		DateTime forMinute = time.withMillisOfSecond(0).withSecondOfMinute(0);
		long minutesBeforeLatest = new Duration(forMinute, latestTime).getStandardMinutes();
		if (minutesBeforeLatest < 0 || minutesBeforeLatest > Integer.MAX_VALUE)
		{
			//TODO: handle this error
		}
		return (int) minutesBeforeLatest;
	}

	@Override
	DateTime normalise(DateTime time)
	{
		return time.withMillisOfSecond(0).withSecondOfMinute(0);
	}

	@Override
	public StringBuilder googleJavascriptData()
	{
		StringBuilder sb = new StringBuilder("({");
		sb.append("cols: [{id: 'hour', label: 'Hour', type: 'datetime'},");
		sb.append("{id: 'sum', label: 'Sum', type: 'number'},");
		sb.append("{id: 'sum_cert', type: 'boolean', role: 'certainty'},");
		sb.append("{id: 'avg', label: 'Average', type: 'number'},");
		sb.append("{id: 'avg_cert', type: 'boolean', role: 'certainty'},");
		sb.append("{id: 'qty', label: 'Quantity', type: 'number'},");
		sb.append("{id: 'qty_cert', type: 'boolean', role: 'certainty'},");
		sb.append("{id: 'min', label: 'Minimum', type: 'number'},");
		sb.append("{id: 'min_cert', type: 'boolean', role: 'certainty'},");
		sb.append("{id: 'max', label: 'Maximum', type: 'number'},");
		sb.append("{id: 'max_cert', type: 'boolean', role: 'certainty'}");
		sb.append("],");
		sb.append("'rows':[");
		DateTime printTime = this.latestTime.minusMinutes(this.getSize());
		for (Statistics s : this)
		{
			boolean certaintyB = true;
			for (Interval ivl : unavailableTimes)
			{
				Interval ivl2 = new Interval(printTime, printTime.plusMinutes(1).minusMillis(1));
				if (ivl.overlaps(ivl2))
				{
					certaintyB = false;
					break;
				}
			}
			String certainty = (certaintyB) ? "true" : "false";
			sb.append("{c:[{v:'");
			sb.append(printTime.getMillis()); //Date
			sb.append("', f:'");
			sb.append(printTime.toString("yyyy-MM-dd HH:mm"));//String Date
			sb.append("'},");
			sb.append("{v:'");
			sb.append(s.getSum());
			sb.append("'},");
			sb.append("{v:'");
			sb.append(certainty);
			sb.append("'},");
			sb.append("{v:'");
			sb.append(((float)s.getSum()) / ((float)s.getQty()));
			sb.append("'},");
			sb.append("{v:'");
			sb.append(certainty);
			sb.append("'},");
			sb.append("{v:'");
			sb.append(s.getQty());
			sb.append("'},");
			sb.append("{v:'");
			sb.append(certainty);
			sb.append("'},");
			sb.append("{v:'");
			sb.append(s.getMin());
			sb.append("'},");
			sb.append("{v:'");
			sb.append(certainty);
			sb.append("'},");
			sb.append("{v:'");
			sb.append(s.getMax());
			sb.append("'}]},");
			sb.append("{v:'");
			sb.append(certainty);
			sb.append("'},");
			printTime = printTime.plusMinutes(1);
		}
		sb.deleteCharAt(sb.length() - 1); //Delete the last character (the comma)
		sb.append("]})");
		return sb;
	}

	/**
	 * @param unavailableTimes the unavailableTimes to set
	 */
	public void setUnavailableTimes(List<Interval> unavailableTimes)
	{
		this.unavailableTimes = unavailableTimes;
	}
}
